<template>
    <tnxel-submit-form ref="form" :model="model" :rules="rules">
        <el-form-item label="所属应用" v-if="!project.isSingleArch()">
            <ModelingAppSelect v-model="modelAppName"/>
        </el-form-item>
        <el-form-item label="包名" prop="packageName" class="new-error-line">
            <el-input v-model="model.packageName"/>
        </el-form-item>
        <el-form-item label="类名" prop="simpleName" class="new-error-line">
            <el-input v-model="model.simpleName" @input="onSimpleNameInput"/>
        </el-form-item>
        <el-form-item label="abstract" prop="abstractClass" class="new-error-line"
            v-if="model.kind !== TypeKind.ENUM.name">
            <tnxel-enum-select v-model="model.abstractClass"
                type="Boolean"
                selector="radio"
                :change="resetPrimaryTypeId"
            />
        </el-form-item>
        <el-form-item label="父类" prop="superClassId" class="new-error-line"
            v-if="!TypeKind.ENUM.equals(clazz.kind)">
            <LogicTypeSelect v-model="model.superClassId"
                :app="app"
                :kind="thisKind"
                extended
                v-if="app && thisKind"/>
        </el-form-item>
        <el-form-item label="性质" prop="type">
            <tnxel-enum-select v-model="model.kind"
                type="TypeKind"
                :subtype="superKind ? ('super-' + superKind.name.toLowerCase()) : 'standard'"
                selector="radio"
                :change="resetPrimaryTypeId"
                v-if="clazz.kind.supports('standard')">
                <template #option="{item}">
                    <div class="flex-v-center">
                        <NodeIcon :type="item.key"/>
                        <span class="ms-1">{{ item.caption }}</span>
                    </div>
                </template>
            </tnxel-enum-select>
            <template v-else>
                <tnxel-enum-view type="TypeKind" :item-key="clazz.kind.toString()"/>
                <span class="form-item-tip">性质不可更改</span>
            </template>
        </el-form-item>
        <el-form-item label="泛型声明" prop="declaredGenericTypes" v-if="model.kind === TypeKind.PLAIN.name">
            <GenericTypeDeclare v-model="model.declaredGenericTypes" :app="app" v-if="app"/>
        </el-form-item>
        <el-form-item label="泛型具化" prop="instantiatedGenericTypes" v-if="superClass?.declaredGenericTypes?.length">
            <GenericTypeInstantiate v-model="model.instantiatedGenericTypes"
                :app="app"
                :limited="superClass.declaredGenericTypes"
                :declared="model.declaredGenericTypes"
                v-if="app"/>
        </el-form-item>
        <el-form-item label="主键类型" prop="primary1TypeId" class="new-error-line"
            v-if="model.kind === TypeKind.UNITY.name">
            <div class="flex-v-center" v-if="superPrimaryTypeIds.length">
                <ClassNameView :app="app" :class-id="superPrimaryTypeIds[0]" simple :openable="false"/>
                <span class="form-item-tip">由父类决定</span>
            </div>
            <LogicTypeSelect v-model="model.primary1TypeId"
                :app="app"
                :kind="thisKind"
                primary
                :clearable="model.abstractClass"
                v-else-if="app && thisKind"/>
        </el-form-item>
        <el-form-item label="左主键类型" prop="primary1TypeId" class="new-error-line"
            v-if="model.kind === TypeKind.RELATION.name">
            <div class="flex-v-center" v-if="superPrimaryTypeIds.length">
                <ClassNameView :app="app" :class-id="superPrimaryTypeIds[0]" simple :openable="false"/>
                <span class="form-item-tip">由父类决定</span>
            </div>
            <LogicTypeSelect v-model="model.primary1TypeId"
                :app="app"
                :kind="thisKind"
                primary
                :clearable="model.abstractClass"
                v-else-if="app && thisKind"/>
        </el-form-item>
        <el-form-item label="右主键类型" prop="primary2TypeId" class="new-error-line"
            v-if="model.kind === TypeKind.RELATION.name">
            <div class="flex-v-center" v-if="superPrimaryTypeIds.length">
                <ClassNameView :app="app" :class-id="superPrimaryTypeIds[1]" simple :openable="false"/>
                <span class="form-item-tip">由父类决定</span>
            </div>
            <LogicTypeSelect v-model="model.primary2TypeId"
                :app="app"
                :kind="thisKind"
                primary
                :clearable="model.abstractClass"
                v-else-if="app && thisKind"/>
        </el-form-item>
        <el-form-item label="显示名" prop="caption" class="new-error-line mb-0">
            <el-input v-model="model.caption"/>
        </el-form-item>
    </tnxel-submit-form>
</template>

<script>
import tnx from '@/tnx.js';
import EntityClass from '@/logic/modeling/entity/EntityClass.js';
import TypeKind from '@/logic/modeling/enums/TypeKind.js';
import {LONG_CLASS_NAME} from '@/logic/modeling/util/dependency-lib-jdk.js';

import rules from './class-rules.js';
import NodeIcon from './components/NodeIcon.vue';
import ClassNameView from './components/ClassNameView.vue';
import ModelingAppSelect from './components/ModelingAppSelect.vue';
import LogicTypeSelect from './components/LogicTypeSelect.vue';
import GenericTypeDeclare from './components/GenericTypeDeclare.vue';
import GenericTypeInstantiate from './components/GenericTypeInstantiate.vue';

export default {
    components: {
        NodeIcon,
        ClassNameView,
        ModelingAppSelect,
        LogicTypeSelect,
        GenericTypeDeclare,
        GenericTypeInstantiate,
    },
    props: {
        appName: {
            type: String,
            required: true,
        },
        classId: {
            type: String,
            required: true,
        },
        after: Function,
    },
    data() {
        let app = tnx.app.global.modelingProject.findApp(this.appName);
        let clazz = app.findClass(this.classId);
        let primary1TypeId = '';
        let primary2TypeId = '';
        if (TypeKind.UNITY.equals(clazz.kind)) {
            let primaryProperty = clazz.properties.find(p => p.primary);
            primary1TypeId = primaryProperty?.typeId || (clazz.abstractClass ? '' : LONG_CLASS_NAME);
        } else if (TypeKind.RELATION.equals(clazz.kind)) {
            let primaryProperties = clazz.properties.filter(p => p.primary);
            primary1TypeId = primaryProperties[0]?.typeId || (clazz.abstractClass ? '' : 'long');
            primary2TypeId = primaryProperties[1]?.typeId || (clazz.abstractClass ? '' : 'long');
        }
        return {
            TypeKind: TypeKind,
            modelAppName: this.appName,
            clazz: clazz,
            model: {
                superClassId: clazz.superClassId || '',
                kind: clazz.kind.name,
                declaredGenericTypes: clazz.declaredGenericTypes || [],
                instantiatedGenericTypes: clazz.instantiatedGenericTypes || [],
                packageName: clazz.packageName || '',
                simpleName: clazz.simpleName || '',
                primary1TypeId: primary1TypeId,
                primary2TypeId: primary2TypeId,
                abstractClass: clazz.abstractClass || false,
                caption: clazz.caption || '',
            },
        };
    },
    computed: {
        project() {
            return tnx.app.global.modelingProject;
        },
        rules() {
            if (!this.model.abstractClass) { // 非抽象类才需要添加主键类型规则
                if (this.model.kind === TypeKind.UNITY.name) {
                    return Object.assign({}, rules, {
                        primary1TypeId: [tnx.app.validator.requiredRule],
                    });
                } else if (this.model.kind === TypeKind.RELATION.name) {
                    return Object.assign({}, rules, {
                        primary1TypeId: [tnx.app.validator.requiredRule],
                        primary2TypeId: [tnx.app.validator.requiredRule],
                    });
                }
            }
            return rules;
        },
        app() {
            return this.project.findApp(this.modelAppName);
        },
        thisKind() {
            if (this.model.kind) {
                return TypeKind.valueOf(this.model.kind);
            }
            return null;
        },
        superClass() {
            if (this.model.superClassId && this.app) {
                return this.app.findClass(this.model.superClassId, true, true);
            }
            return null;
        },
        superKind() {
            return this.superClass ? this.superClass.getKind() : null;
        },
        superPrimaryTypeIds() {
            return this.app ? this.app.getPrimaryLogicTypeIds(this.superClass) : [];
        },
    },
    methods: {
        dialog() {
            return {
                title: '修改模型类',
                width: 420,
                type: 'confirm',
                click: this.toSubmit,
            }
        },
        onSimpleNameInput() {
            if (this.model.simpleName.length === 1) {
                this.model.simpleName = this.model.simpleName.toUpperCase();
            }
        },
        resetPrimaryTypeId() {
            if (this.model.kind === TypeKind.UNITY.name) {
                this.model.primary1TypeId = this.model.abstractClass ? '' : LONG_CLASS_NAME;
                this.model.primary2TypeId = '';
            } else if (this.model.kind === TypeKind.RELATION.name) {
                this.model.primary1TypeId = this.model.abstractClass ? '' : 'long';
                this.model.primary2TypeId = this.model.abstractClass ? '' : 'long';
            } else {
                this.model.primary1TypeId = '';
                this.model.primary2TypeId = '';
            }
        },
        toSubmit(yes, close) {
            if (yes) {
                this.$refs.form.toSubmit(form => {
                    let primary1TypeId = this.superPrimaryTypeIds[0] || this.model.primary1TypeId;
                    let primary2TypeId = this.superPrimaryTypeIds[1] || this.model.primary2TypeId;
                    if (this.model.kind === TypeKind.RELATION.name) {
                        if ((primary1TypeId && !primary2TypeId) || (!primary1TypeId && primary2TypeId)) {
                            tnx.error('关系的主键类型必须都指定或都不指定');
                            form.disable(false);
                            return false;
                        }
                    }
                    // 实体类的性质如果有改动，需提醒主键属性变动
                    if (this.model.kind !== this.clazz.kind.name && this.clazz instanceof EntityClass
                        && this.clazz.existsPrimaryProperty()) {
                        let message = '性质已改动，原来的主键属性将被';
                        if (this.model.kind === TypeKind.UNITY.name || this.model.kind === TypeKind.RELATION.name) {
                            message += '重置';
                        } else {
                            message += '删除';
                        }
                        message += '，是否继续？';
                        tnx.confirm(message).then(yes => {
                            if (yes) {
                                this.submit(form, close, primary1TypeId, primary2TypeId);
                            } else {
                                form.disable(false);
                            }
                        });
                    } else {
                        this.submit(form, close, primary1TypeId, primary2TypeId);
                    }
                });
                return false;
            }
        },
        submit(form, close, primary1TypeId, primary2TypeId) {
            let modelKind = TypeKind.validate(this.model.kind);
            let model = Object.assign({}, this.model);
            delete model.primary1TypeId;
            delete model.primary2TypeId;
            delete model.superClassId;
            delete model.properties;
            if (modelKind.supports('standard')) {
                model.superClassId = this.model.superClassId || ''; // 父类可能被置为undefined
                let properties = [];
                // 如果继承体系中不存在主键属性，则需处理主键属性
                if (!this.app.existsPrimaryProperty(model.superClassId)) {
                    if (this.model.kind === TypeKind.UNITY.name) {
                        if (primary1TypeId) {
                            let primaryProperty = null;
                            // 性质无变化，则修改原有的主键属性
                            if (this.model.kind === this.clazz.kind.name) {
                                primaryProperty = this.clazz.properties.find(p => p.primary);
                            }
                            if (primaryProperty) {
                                primaryProperty.typeId = primary1TypeId;
                            } else {
                                primaryProperty = {
                                    name: 'id',
                                    typeId: primary1TypeId,
                                    primary: true,
                                };
                            }
                            properties.push(primaryProperty);
                        }
                    } else if (this.model.kind === TypeKind.RELATION.name) {
                        // 关系的主键类型必须都指定才有效
                        if (primary1TypeId && primary2TypeId) {
                            let primaryProperties = this.clazz.properties.filter(p => p.primary);

                            let leftPrimaryProperty = null;
                            let rightPrimaryProperty = null;
                            // 性质无变化，则修改原有的主键属性
                            if (this.model.kind === this.clazz.kind.name) {
                                leftPrimaryProperty = primaryProperties[0];
                                rightPrimaryProperty = primaryProperties[1];
                            }
                            if (leftPrimaryProperty) {
                                leftPrimaryProperty.typeId = primary1TypeId;
                            } else {
                                leftPrimaryProperty = {
                                    name: 'leftId',
                                    typeId: primary1TypeId,
                                    primary: true,
                                };
                            }
                            if (rightPrimaryProperty) {
                                rightPrimaryProperty.typeId = primary2TypeId;
                            } else {
                                rightPrimaryProperty = {
                                    name: 'rightId',
                                    typeId: primary2TypeId,
                                    primary: true,
                                };
                            }
                            properties.push(leftPrimaryProperty, rightPrimaryProperty);
                        }
                    }
                }
                // 加入原有的非主键属性
                properties.push(...this.clazz.properties.filter(p => !p.primary));
                model.properties = properties;
            }
            if (this.after(this.modelAppName, model) !== false) {
                close();
            } else {
                form.disable(false);
            }
        },
    }
}
</script>

<style scoped>

</style>
